﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Poker24Demo
{
    
    /// <summary>
    /// 基础块
    /// </summary>
    public abstract class PokerBlock
    {

       

    }

    /// <summary>
    /// 计算块
    /// </summary>
    public abstract class CalcBlock : PokerBlock
    {

        public abstract string Formula();

        public abstract double Calc();

        /// <summary>
        /// 交换律
        /// </summary>
        public virtual string LawOfExchange()
        {
            return null;
        }



        public override bool Equals(object obj)
        {
            if (obj == null)//步骤1
                return false;
            if (this.GetType() != obj.GetType())//步骤3
                return false;
            return Equals((CalcBlock)obj);//步骤4
        }

        public bool Equals(CalcBlock obj)
        {
            if (obj == null)//步骤1
                return false;
            if (ReferenceEquals(this, obj))//步骤2
                return true;
            return (Formula() == obj.Formula());

        }



        public static bool operator ==(CalcBlock p1, CalcBlock p2)
        {
            if (ReferenceEquals(p1, null))
                return ReferenceEquals(p2, null);
            return (p1.Equals(p2));
        }
        public static bool operator !=(CalcBlock p1, CalcBlock p2)
        {
            return !(p1 == p2);
        }


        public override int GetHashCode()
        {
            string a = Formula();
            return a.GetHashCode();

        }
    }

    /// <summary>
    /// 符号块
    /// </summary>
    public sealed class SignBlock : PokerBlock
    {
        private string Sign { get; set; }

        public SignBlock(string sign)
        {
            this.Sign = sign;

        }

        /// <summary>
        /// 比较优先级  大于0  优先级高，等于0相等，小于0 优先级小
        /// </summary>
        public int ComparePriority(SignBlock sb)
        {
            return this.GetPriority() - sb.GetPriority();
        }

        public Boolean IsLeftBracket
        {
            get
            {
                return Sign == "(";
            }
        }

        public Boolean IsRightBracket
        {
            get
            {
                return Sign == ")";
            }
        }

        public int GetPriority()
        {
            int p = 0;
            switch (Sign)
            {
                case "+":
                    p = 10;
                    break;
                case "-":
                    p = 10;
                    break;
                case "*":
                    p = 20;
                    break;
                case "/":
                    p = 20;
                    break;
            }
            return p;
        }

        public CalcBlock Merge(CalcBlock a, CalcBlock b)
        {
            CalcBlock res = null;
            switch (Sign)
            {
                case "+":
                    res = new AddCalcBlock(a, b);
                    break;
                case "-":
                    res = new SubCalcBlock(a, b);
                    break;
                case "*":
                    res = new MultiCalcBlock(a, b);
                    break;
                case "/":
                    res = new DivisionCalcBlock(a, b);
                    break;
            }

            return res;
        }
    }

    /// <summary>
    /// 数值块
    /// </summary>
    public sealed class ValueBlock : CalcBlock
    {

        private double Value { get; set; }

        public ValueBlock(double value)
        {
            this.Value = value;
        }

        public override double Calc()
        {
            return Value;
        }

        public override string Formula()
        {
            return Value.ToString();
        }
    }

    /// <summary>
    /// 加法块
    /// </summary>
    public sealed class AddCalcBlock : CalcBlock
    {
        private CalcBlock LeftBlock { get; set; }
        private CalcBlock RightBlock { get; set; }

        public AddCalcBlock(CalcBlock leftBlock, CalcBlock rightBlock)
        {
            this.LeftBlock = leftBlock;
            this.RightBlock = rightBlock;
        }

        public override double Calc()
        {
            return LeftBlock.Calc() + RightBlock.Calc();
        }

        public override string Formula()
        {
            return $"{LeftBlock.Formula()} + {RightBlock.Formula()}";
        }

        public override string LawOfExchange()
        {
            return $"{RightBlock.Formula()} + {LeftBlock.Formula()}";
        }
    }

    /// <summary>
    /// 减法块
    /// </summary>
    public sealed class SubCalcBlock : CalcBlock
    {
        private CalcBlock LeftBlock { get; set; }
        private CalcBlock RightBlock { get; set; }

        public SubCalcBlock(CalcBlock leftBlock, CalcBlock rightBlock)
        {
            this.LeftBlock = leftBlock;
            this.RightBlock = rightBlock;
        }

        public override double Calc()
        {
            return LeftBlock.Calc() - RightBlock.Calc();
        }

        public override string Formula()
        {
            if (RightBlock is SubCalcBlock)
            {
                return $"{LeftBlock.Formula()} - ( {RightBlock.Formula()} )";
            }

            return $"{LeftBlock.Formula()} - {RightBlock.Formula()}";
        }

    }

    /// <summary>
    /// 乘法块
    /// </summary>
    public sealed class MultiCalcBlock : CalcBlock
    {
        private CalcBlock LeftBlock { get; set; }
        private CalcBlock RightBlock { get; set; }

        public MultiCalcBlock(CalcBlock leftBlock, CalcBlock rightBlock)
        {
            this.LeftBlock = leftBlock;
            this.RightBlock = rightBlock;
        }

        public override double Calc()
        {
            return LeftBlock.Calc() * RightBlock.Calc();
        }

        public override string Formula()
        {
            string left = "";
            string right = "";
            if (LeftBlock is AddCalcBlock || LeftBlock is SubCalcBlock)
            {
                left = $"( {LeftBlock.Formula()} )";
            }
            else
            {
                left = LeftBlock.Formula();
            }

            if (RightBlock is AddCalcBlock || RightBlock is SubCalcBlock)
            {
                right = $"( {RightBlock.Formula()} )";
            }
            else
            {
                right = RightBlock.Formula();
            }

            return $"{left} * {right}";
        }

        public override string LawOfExchange()
        {
            string left = "";
            string right = "";
            if (LeftBlock is AddCalcBlock || LeftBlock is SubCalcBlock)
            {
                left = $"( {LeftBlock.Formula()} )";
            }
            else
            {
                left = LeftBlock.Formula();
            }

            if (RightBlock is AddCalcBlock || RightBlock is SubCalcBlock)
            {
                right = $"( {RightBlock.Formula()} )";
            }
            else
            {
                right = RightBlock.Formula();
            }

            return $"{right} * {left}";
        }

    }

    /// <summary>
    /// 除法块
    /// </summary>
    public sealed class DivisionCalcBlock : CalcBlock
    {
        private CalcBlock LeftBlock { get; set; }
        private CalcBlock RightBlock { get; set; }
        public DivisionCalcBlock(CalcBlock leftBlock, CalcBlock rightBlock)
        {
            this.LeftBlock = leftBlock;
            this.RightBlock = rightBlock;
        }

        public override double Calc()
        {
            return LeftBlock.Calc() / RightBlock.Calc();
        }

        public override string Formula()
        {
            string left = "";
            string right = "";
            if (LeftBlock is AddCalcBlock || LeftBlock is SubCalcBlock)
            {
                left = $"( {LeftBlock.Formula()} )";
            }
            else
            {
                left = LeftBlock.Formula();
            }

            if (RightBlock is AddCalcBlock || RightBlock is SubCalcBlock)
            {
                right = $"( {RightBlock.Formula()} )";
            }
            else
            {
                right = RightBlock.Formula();
            }

            return $"{left} / {right}";
        }

    }


    public sealed class CalcPokerBlockComparer : IEqualityComparer<CalcBlock>
    {
        public bool Equals(CalcBlock x, CalcBlock y)
        {
            if (x == null)
                return y == null;
            return x == y;
        }

        public int GetHashCode(CalcBlock obj)
        {
            if (obj == null)
                return 0;
            return obj.GetHashCode();
        }
    }
}
